<?php

namespace SunAdmin\Task\jobs;

use SunAdmin\Common\Utils;
use SunAdmin\Model\TimerTaskLogModel;
use SunAdmin\Model\TimerTaskModel;
use Throwable;

abstract class JobBaseAbstract
{

    protected array $timerTask = [];

    /**
     * 任务实际执行流程调用该方法即可
     * 如果直接调用任务jos类中的run方法将会报错,因为run方法为protected,目的是进允许exec方法调用
     * @param int $taskId 任务id
     */
    final public function run(int $taskId)
    {
        $startTime = microtime(true);
        $startMemory = memory_get_usage(true);
        $startTimeStr = Utils::timeToStr();
        $endTimeStr = '';
        $execTime = 0;
        $execMemory = 0;
        $timerTask = TimerTaskModel::find($taskId);
        if (!$timerTask) {
            throw new \Exception("id为{$taskId}的任务不存在");
        }
        $this->timerTask = $timerTask->toArray();
        $this->timerTask['run_status'] = 'running';
        $this->timerTask['last_run_time'] = $startTimeStr;
        try {
            // 先更新数据库状态
            TimerTaskModel::update($this->timerTask);
            //执行任务
            $this->main();
            $this->timerTask['run_status'] = 'success';
        } catch (Throwable $e) {
            $this->timerTask['failed_executions'] += 1;
            $this->timerTask['run_status'] = 'error';
            $this->log("任务执行失败,".$e->getMessage().$e->getTraceAsString(),'error');
        } finally {
            // 记录结束时间和计算执行数据
            $endTime = microtime(true);
            $endMemory = memory_get_usage(true);
            $endTimeStr = Utils::timeToStr();
            $execTime = round(($endTime - $startTime) * 1000, 2); // 转换为毫秒，保留2位小数
            $execMemory = $endMemory - $startMemory; // 内存增量（字节）

            //更新任务状态
            TimerTaskModel::update($this->timerTask);
            //记录日志
            if($this->timerTask['log_level'] == 'full' || ( $this->timerTask['log_level'] == 'error_only' && $this->timerTask['run_status'] != 'success')){
                TimerTaskLogModel::create([
                    'task_id' => $this->timerTask['id'],
                    'exec_time' => $execTime,
                    'exec_memory' => $execMemory,
                    'start_time' => $startTimeStr,
                    'end_time' => $endTimeStr,
                    'status' => $this->timerTask['run_status'] == 'success' ? 1 : 0,
                    'add_time' => Utils::timeToStr(),
                    'message' => $this->execLogList
                ]);
            }
        }
    }

    abstract protected function main();

    protected $execLogList = [];

    protected function log($msg, $level = 'info')
    {
        $data = [
            'msg' => $msg,
            'level' => $level,
            'time' => Utils::timeToStr()
        ];
        $this->execLogList[] = $data;
        if($this->timerTask['log_level'] == 'full' || ( $this->timerTask['log_level'] == 'error_only' && $level == 'error')){
            trace("[{$data['time']}] | [{$this->timerTask['name']}] | {$data['level']}] | {$data['msg']}",$level);
        }
    }
}